package day76;

import java.util.*;

public class Solutopn {
    public class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode() {}
      TreeNode(int val) { this.val = val; }
      TreeNode(int val, TreeNode left, TreeNode right) {
          this.val = val;
          this.left = left;
          this.right = right;
      }
  }
    public boolean isInterleave(String s1, String s2, String s3) {
        // dp[i][j] 表示s1的前i个元素和s2的前j个元素能否组成s3的前i+j个元素
        // dp[i][j] = (dp[i-1][j] && s1[i] == s3[i+j]) || (dp[i][j-1] && s2[j] == s3[i+j])
        // 初始化 dp[0][0] = true
        int n = s1.length(),m = s2.length(),t = s3.length();
        if(n + m != t)return false;
        boolean[][] dp = new boolean[n+1][m+1];
        dp[0][0] = true;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                int p = i + j - 1;
                if(i>0) {
                    dp[i][j] = dp[i][j] || (dp[i-1][j] && s1.charAt(i-1) == s3.charAt(p));
                }
                if(j>0) {
                    dp[i][j] = dp[i][j] || (dp[i][j-1] && s2.charAt(j-1) == s3.charAt(p));
                }
            }
        }
        return dp[n][m];
    }
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] dp = new int[n][n];
        dp[0][0] = triangle.get(0).get(0);
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                // j == i
                if(j == i) {
                    dp[i][j] = dp[i-1][j-1] + triangle.get(i).get(j);
                } else if(j == 0){
                    dp[i][j] = dp[i-1][j] + triangle.get(i).get(j);
                } else {
                    dp[i][j] = Math.min(dp[i-1][j],dp[i-1][j-1]) + triangle.get(i).get(j);
                }
            }
        }
        int ans = dp[n-1][0];
        for (int i = 0; i < n; i++) {
            ans = Math.min(ans,dp[n-1][i]);
        }
        return ans;
    }
    public int maxProfit(int[] prices) {
        // dp[i][0] 表示第i天持有股票的最大利润
        // dp[i][1] 表示第i天不持有股票的最大利润
        // dp[i][0] = max(dp[i-1][0],dp[i-1][1]-prices[i]);
        // dp[i][1] = max(dp[i-1][1],dp[i-1][1]+prices[i]);
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = -prices[0];
        for (int i = 1; i < n; i++) {
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return dp[n-1][1];
    }
    public List<List<String>> partition(String s) {
        // 分割回文字符串
        // 枚举所有的子集
        // 回溯
        // 动态规划预处理
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        for (int i = n-1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if(j - i <= 1) {
                    dp[i][j] = s.charAt(i) == s.charAt(j);
                } else {
                    dp[i][j] = s.charAt(i) == s.charAt(j) && dp[i+1][j-1];
                }
            }
        }
        List<List<String>> ans = new ArrayList<>();
        trackBack(s,0,ans,new ArrayList<>(),dp);
        return ans;
    }
    private void trackBack(String s,int start,List<List<String>> ans,List<String> path,boolean[][] isVail) {
        if(start == s.length()) {
            ans.add(new ArrayList<>(path));
            return;
        }
        // 枚举切割的位置
        for (int i = start; i < s.length(); i++) {
            if(isVail[start][i]) {
                path.add(s.substring(start,i+1));
                trackBack(s,i+1,ans,path,isVail);
                path.remove(path.size()-1);
            }
        }
    }
    public int rob(int[] nums) {
        // dp[i][0] 表示第偷第i个房子的最大值
        // dp[i][1] 表示不偷第i个房子的最大值
        // dp[i][0] = dp[i-1][1] + nums[i]
        // dp[i][1] = Math.max(dp[i-1][0],dp[i-1][1])
        int n = nums.length;
        int[][] dp = new int[n][2];
        dp[0][0] = nums[0];
        dp[0][1] = 0;
        for (int i = 1; i < n; i++) {
            dp[i][0] = dp[i-1][1] + nums[i];
            dp[i][1] = Math.max(dp[i-1][0],dp[i-1][1]);
        }
        return Math.max(dp[n-1][0],dp[n-1][1]);
    }
    public int deleteAndEarn(int[] nums) {
        int maxVal = 0;
        for (int val : nums) {
            maxVal = Math.max(maxVal, val);
        }
        int[] sum = new int[maxVal + 1];
        for (int val : nums) {
            sum[val] += val;
        }
        return rob(sum);
    }
    public int minFallingPathSum(int[][] matrix) {
        // dp[i][j] 表示下降到第i行j列的最小代价
        // dp[i][j] Math.min(dp[i-1][j-1],dp[i-1][j],dp[i][j+1]);
        int n = matrix.length;
        int m = matrix[0].length;
        int[][] dp = new int[n][m];
        for (int i = 0; i < m; i++) {
            dp[0][i] = matrix[0][i];
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int min = dp[i-1][j];
                if(j != 0) {
                    min = Math.min(min,dp[i-1][j-1]);
                }
                if(j != m-1) {
                    min = Math.min(min,dp[i-1][j+1]);
                }
                dp[i][j] = min + matrix[i][j];
            }
        }
        int min = dp[n-1][0];
        for (int i = 0; i < m; i++) {
            min = Math.min(min,dp[n-1][i]);
        }
        return min;
    }
    public int maximalSquare(char[][] matrix) {
        // dp[i][j] 表示以[i,j] 为右下角的最大正方形的边长
        // dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]) + 1;
        int m = matrix.length,n = matrix[0].length;
        int[][] dp = new int[m][n];
        int maxLen = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(matrix[i][j] == '0') {
                    dp[i][j] = 0;
                } else {
                    if(i ==0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]);
                        dp[i][j] = Math.min(dp[i][j],dp[i-1][j-1]);
                        dp[i][j]++;
                        maxLen = Math.max(maxLen,dp[i][j]);
                    }
                }
            }
        }
        return maxLen * maxLen;
    }
    public boolean wordBreak(String s, List<String> wordDict) {
        // 动态规划
        // dp[i] 表示 s中的前i部分 能不能由wordict中的元素组成

        boolean[] dp = new boolean[s.length()];
        // dp数组初始化
        for (String word: wordDict) {
            if(s.startsWith(word)) {
                dp[word.length()-1] = true;
            }
        }
        for (int i = 0; i < s.length(); i++) {
            for (String word: wordDict) {
                if(i>=word.length() && word.equals(s.substring(i-word.length()+1,i+1))) {
                    dp[i] |= dp[i-word.length()];
                }
            }
        }
        return dp[s.length()-1];
    }
    public int longestPalindromeSubseq(String s) {
        // dp[i][j] 表示 s[i,j] 之间的最长回文子串
        int m = s.length();
        int[][] dp = new int[m][m];
        for (int i = m-1; i >= 0; i--) {
            for (int j = i; j < m; j++) {
                if(i == j) {
                    dp[i][j] = 1;
                } else if(j-i == 1) {
                    if(s.charAt(i) == s.charAt(j)) dp[i][j] = 2;
                    else dp[i][j] = 1;
                } else {
                    if(s.charAt(i) == s.charAt(j)) {
                        dp[i][j] = dp[i+1][j-1] + 2;
                    } else {
                        dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                    }
                }
            }
        }
        return dp[0][m-1];
    }
    public List<Integer> diffWaysToCompute(String expression) {
        return dfs(0,expression.length()-1,expression,new List[expression.length()][expression.length()]);
    }
    private List<Integer> dfs(int start,int end,String exp,List<Integer>[][] memo) {
        if(memo[start][end] != null) {
            return memo[start][end];
        }
        boolean hasOp = false;
        List<Integer> ans = new ArrayList<>();
        for (int i = start; i <= end; i++) {
            if(exp.charAt(i) > '9' || exp.charAt(i) < '0') {
                List<Integer> left = dfs(start,i-1,exp,memo);
                List<Integer> right = dfs(i+1,end,exp,memo);
                hasOp = true;
                for (int l = 0; l < left.size(); l++) {
                    for (int r = 0; r < right.size(); r++) {
                        int val = opration(left.get(l),right.get(r),exp.charAt(i));
                        ans.add(val);
                    }
                }
            }
        }
        if(!hasOp) {
            ans.add(Integer.parseInt(exp.substring(start,end+1)));
        } // 表达式中不含运算符 直接返回数值
        memo[start][end] = ans;
        return ans;
    }
    private int opration(int a,int b,char c) {
        if(c == '+') return a + b;
        if(c == '-') return a - b;
        return a * b;
    }
    public int maxProduct(int[] nums) {
        int max = Integer.MIN_VALUE,iMax = 1,iMin = 1;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] < 0) {
                int tmp = iMax;
                iMax = iMin;
                iMin = tmp;
            }
            iMax = Math.max(iMax*nums[i],nums[i]);
            iMin = Math.min(iMin*nums[i],nums[i]);

            max = Math.max(max,iMax);
        }
        return max;
    }
//    public int longestPalindromeSubseq(String s) {
//        // 删除某些字符或者不删除某些字符形成的序列
//        // 回溯暴力搜索
//        int[] ans = new int[1];
//        dfs(s,0,new StringBuilder(),ans);
//        return ans[0];
//    }
//    private void dfs(String s,int startIndex,StringBuilder sb,int[] ans) {
//        if(check(sb.toString())) {
//            ans[0] = Math.max(ans[0],sb.length());
//        }
//        for (int i = startIndex; i < s.length(); i++) {
//            sb.append(s.charAt(i));
//            dfs(s,i+1,sb,ans);
//            sb.deleteCharAt(sb.length()-1);
//        }
//    }
//    private boolean check(String s) {
//        int i = 0,j = s.length()-1;
//        while (i < j) {
//            if(s.charAt(i++) != s.charAt(j--)) return false;
//        }
//        return true;
//    }
    // 记忆化搜索
//    public boolean wordBreak(String s, List<String> wordDict) {
//        return check(s,new HashSet<>(wordDict),new int[s.length()],0);
//    }
//    private boolean check(String s,Set<String> wordict,int[] memo,int startIndex) {
//        if(startIndex == s.length()) return true;
//        if(memo[startIndex] != 0) return memo[startIndex] == 1;
//
//        boolean ans = false;
//        for (int i = startIndex; i < s.length(); i++) {
//            if(wordict.contains(s.substring(startIndex,i+1))) {
//                ans |= check(s,wordict,memo,i+1);
//            }
//        }
//        if(ans) memo[startIndex] = 1;
//        else memo[startIndex] = 2;
//        return ans;
//    }

//    public boolean wordBreak(String s, List<String> wordDict) {
//        // 回溯，枚举切割的位置
//        Set<String> set = new HashSet<>(wordDict);
//        return dfs(s,0,set);
//    }
//    private boolean dfs(String s,int startIndex,Set<String> wordDict) {
//        // 枚举切割的位置
//        if(startIndex == s.length()) return true;
//        boolean ans = false;
//        for (int i = startIndex; i < s.length(); i++) {
//            if(wordDict.contains(s.substring(startIndex,i+1))) {
//                ans |= dfs(s,i+1,wordDict);
//            }
//        }
//        return ans;
//    }



    static class Node {
        int val;
        Node next;

        public Node(int val) {
            this.val = val;
        }
    }

    public static void main(String[] args) {
        int n = (1<<20);
        System.out.println((1<<30));
        // 模拟
        Node head = new Node(1);
        Node p = head;
        head.next = head;
        for (int i = 2; i <=n ; i++) {
            Node node = new Node(i);
            p.next = node;
            node.next = head;
            p = p.next;
        }
        p = head;
        int size = n;
        while (p.next != p) {
            Node delete = p.next.next;
            p.next.next = delete.next;
            p = delete.next;
            System.out.println(delete.val);
            size--;
        }
        System.out.println(p.val);
        // 1
        // 3 6 4 2 5 1
        //        System.out.println(head.val);
//        while (p!=head) {
//            System.out.println(p.val);
//            p = p.next;
//        }
    }
}



























